package com.example.handler;

import com.example.bo.SheetBO;
import com.example.config.InitPropertiesConfig;
import com.example.constant.CommonConstant;
import com.example.util.ElasticSearchUtils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
@EnableConfigurationProperties(InitPropertiesConfig.class)
public class StatisticHandler {
    @Autowired
    private ElasticSearchUtils elasticSearchUtils;

    @Autowired
    InitPropertiesConfig initPropertiesConfig;


    public void statisticAccessLog() throws IOException {
        RestHighLevelClient client = elasticSearchUtils.getRestHighLevelClient();
        SearchRequest searchRequest = new SearchRequest(initPropertiesConfig.getAccessIndex());

        LocalDateTime begin=getTime(initPropertiesConfig.getBeginTime());
        LocalDateTime end=getTime(initPropertiesConfig.getEndTime());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("appname","applicationName"))
                .must(QueryBuilders.rangeQuery("@timestamp").gte(begin).lte(end))
        );
        sourceBuilder.aggregation(
                AggregationBuilders
                        .dateHistogram("popular_time")
                        .field("@timestamp")
                        .dateHistogramInterval(DateHistogramInterval.HOUR)
        );
        sourceBuilder.size(0);
        sourceBuilder.timeout(new TimeValue(90000));

        searchRequest.source(sourceBuilder);
        // 4.执行查询
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        // 5.得到查询结果
        SearchHits responseHits = response.getHits();
        long totalHits = responseHits.getTotalHits();
        log.info("total："+totalHits);

        // 6.解析分组查询数据
        ParsedDateHistogram aggregation = (ParsedDateHistogram)response.getAggregations().asMap().get("popular_time");
        List<SheetBO> parse = parse(aggregation);
        System.out.println(parse);
    }

    public List<SheetBO> statisticLogMsg(String appname,String msg) throws IOException, ParseException {
        RestHighLevelClient client = elasticSearchUtils.getRestHighLevelClient();
        SearchRequest searchRequest = new SearchRequest(initPropertiesConfig.getAppIndex());

        LocalDateTime begin=getTime(initPropertiesConfig.getBeginTime());
        LocalDateTime end=getTime(initPropertiesConfig.getEndTime());

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//        sourceBuilder.query(QueryBuilders.boolQuery()
//                .must(QueryBuilders.termQuery("appname","mds"))
//                .must(QueryBuilders.matchQuery("message","Receive Message"))
//                .must(QueryBuilders.rangeQuery("@timestamp").gte(begin).lte(end))
//        );
        sourceBuilder.query(QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("appname",appname))
                .must(QueryBuilders.matchQuery("message",msg))
                .must(QueryBuilders.rangeQuery("@timestamp").gte(begin).lte(end))
        );

        sourceBuilder.aggregation(
                AggregationBuilders
                        .dateHistogram("popular_time")
                        .field("@timestamp")
                        .dateHistogramInterval(DateHistogramInterval.HOUR)
        );

        sourceBuilder.size(0);
        sourceBuilder.timeout(new TimeValue(90000));

        searchRequest.source(sourceBuilder);
        // 4.执行查询
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        // 5.得到查询结果
        SearchHits responseHits = response.getHits();
        long totalHits = responseHits.getTotalHits();
        log.info("total："+totalHits);

        // 6.解析分组查询数据
        ParsedDateHistogram aggregation = (ParsedDateHistogram)response.getAggregations().asMap().get("popular_time");
        return parse(aggregation);
    }

    public List<SheetBO> parse(ParsedDateHistogram aggregation){
        Map<String, SheetBO> map=new HashMap<>();
        List<? extends Histogram.Bucket> buckets = aggregation.getBuckets();
        for (Histogram.Bucket bucket : buckets) {
            String keyAsString = bucket.getKeyAsString();
            long docCount = bucket.getDocCount();
            LocalDateTime parse = LocalDateTime.parse(keyAsString, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern(CommonConstant.pattern);
            String format = dtf.format(parse);
            String[] s = format.split(" ");
            SheetBO mdsSheetBO = map.get(s[0]);
            if (mdsSheetBO==null){
                mdsSheetBO=new SheetBO();
                mdsSheetBO.setDate(s[0]);
            }
            switch (s[1]){
                case CommonConstant.TIME_7:
                    mdsSheetBO.setTime7(docCount);
                    break;
                case CommonConstant.TIME_8:
                    mdsSheetBO.setTime8(docCount);
                    break;
                case CommonConstant.TIME_9:
                    mdsSheetBO.setTime9(docCount);
                    break;
                case CommonConstant.TIME_10:
                    mdsSheetBO.setTime10(docCount);
                    break;
                case CommonConstant.TIME_11:
                    mdsSheetBO.setTime11(docCount);
                    break;
                case CommonConstant.TIME_12:
                    mdsSheetBO.setTime12(docCount);
                    break;
                case CommonConstant.TIME_13:
                    mdsSheetBO.setTime13(docCount);
                    break;
                case CommonConstant.TIME_14:
                    mdsSheetBO.setTime14(docCount);
                    break;
                case CommonConstant.TIME_15:
                    mdsSheetBO.setTime15(docCount);
                    break;
                case CommonConstant.TIME_16:
                    mdsSheetBO.setTime16(docCount);
                    break;
                case CommonConstant.TIME_17:
                    mdsSheetBO.setTime17(docCount);
                    break;
                case CommonConstant.TIME_18:
                    mdsSheetBO.setTime18(docCount);
                    break;
                case CommonConstant.TIME_19:
                    mdsSheetBO.setTime19(docCount);
                    break;
                case CommonConstant.TIME_20:
                    mdsSheetBO.setTime20(docCount);
                    break;
                default:
                    break;
            }
            map.put(s[0],mdsSheetBO);
        }
        ArrayList<SheetBO> mdsSheetBOS = new ArrayList<>(map.values());
        List<SheetBO> collect = mdsSheetBOS.stream()
                .map(v->{
                    v.setTotal(
                            v.getTime7()+ v.getTime8()+v.getTime9()+v.getTime10()
                            + v.getTime11()+v.getTime12()+v.getTime13()+v.getTime14()
                            +v.getTime15()+ v.getTime16()+v.getTime17()+v.getTime19()
                            +v.getTime20()
                    );
                    return v;
                })
                .sorted((v1, v2) -> Integer.parseInt(v1.getDate())-Integer.parseInt(v2.getDate()))
                .collect(Collectors.toList());
        return collect;
    }

    private LocalDateTime getTime(String timeStr){
        String[] times = timeStr.split(CommonConstant.SPLIT_);
        List<Integer> timeList = Arrays.stream(times).map(v -> Integer.parseInt(v)).collect(Collectors.toList());

        LocalDateTime time=LocalDateTime.of(timeList.get(0), timeList.get(1), timeList.get(2), timeList.get(3), timeList.get(4));
        return time;
    }

}
